import { IDocumentProps, IResponseProps } from '@/store/modules/document/types'
import { SupportMethodType } from '@/types/knife4j'
import { MenuProps } from '@/types/menu'
import { renderSvgIcon } from '@/utils/tools'
import { RouteRecordRaw } from 'vue-router'

const basicType = ['string', 'integer', 'number', 'object', 'boolean', 'int32', 'int64', 'float', 'double']

export const getClassName = (value: string) => {
  const regex = new RegExp('#/components/schemas/(.*)$', 'ig')
  const execArr = regex.exec(value)
  if (execArr) {
    return execArr[1]
  }
  return null
}

/**
 * 响应结果处理
 * @param schemaKey
 * @param schemas
 * @param firstKey 根据父节点生成key
 * @param result
 * @param noLoop 是否继续递归的标志，如果为树形数据，则不继续递归
 * @returns
 */
export function dealResponses(schemaKey: string, schemas: Record<string, any>, firstKey?: string, result: any[] = [], noLoop = false) {
  const schemaData = schemas[schemaKey]
  const { properties } = schemaData
  Object.keys(properties).forEach((key, index) => {
    const proObj = properties[key]
    const commonData: any = {
      description: proObj.description,
      name: key,
      type: proObj.type,
      schemaValue: proObj.format,
      key: firstKey ? `${firstKey}-${index + 1}` : `${index + 1}` // 表格展示key
    }
    if (proObj.items && !noLoop) {
      if (proObj.items.$ref) {
        const schemaName = getClassName(proObj.items.$ref)
        if (schemaName) {
          commonData.schemaValue = schemaName
          commonData.children = dealResponses(schemaName as string, schemas, commonData.key, [], schemaName.includes('TreeNode'))
        }
      }
    }
    result.push(commonData)
  })
  return result
}

/**
 * 响应结果处理成json数据
 * @param schemaKey
 * @param schemas
 * @param noLoop
 */
export function dealToJson(schemaKey: string, schemas: Record<string, any>, result: Record<string, any> = {}, noLoop = false) {
  const schemaData = schemas[schemaKey].properties
  Object.keys(schemaData).forEach((key) => {
    const keyObj = schemaData[key]
    const { type = '', items, $ref } = keyObj

    if (type === 'string') {
      result[key] = ''
    } else if (type.includes('int')) {
      result[key] = 0
    } else if (type === 'boolean') {
      result[key] = false
    } else if (type === 'array') {
      if (!items.$ref && !$ref) {
        if (items.type) {
          if (basicType.includes(items.type)) {
            // 基础类型数组，直接赋值为 []
            result[key] = []
          } else {
            // 非基础类型 继续递归查找
            result[key] = []
          }
        }
      } else {
        // 不是基础类型
        const schemaName = getClassName($ref || items.$ref)
        if (schemaName && !noLoop) {
          if (type === 'array') {
            result[key] = [{ ...dealToJson(schemaName, schemas, {}, schemaName.includes('TreeNode')) }]
          }
        } else {
          result.children = [{}]
        }
      }
    }
  })

  return result
}

export function dealProperties(schema: Record<string, any>, isChild?: boolean) {
  const { required: requiredArr = [], type, properties, title = '' } = schema
  if (type === 'object') {
    if (isChild) {
      // ref属性整理为二维数组
      return [
        {
          name: title,
          description: title,
          required: true,
          in: 'body',
          schema: { type: title, format: title },
          children: Object.keys(properties).map((proName) => {
            return {
              ...properties[proName],
              name: proName,
              required: requiredArr.includes(proName) ?? false,
              in: '',
              type: properties[proName].format && properties[proName].format === 'binary' ? 'file' : properties[proName].type
            }
          })
        }
      ]
    }

    return Object.keys(properties).map((proName) => {
      return {
        ...properties[proName],
        name: proName,
        required: requiredArr.includes(proName) ?? false,
        in: 'query',
        type: properties[proName].format && properties[proName].format === 'binary' ? 'file' : properties[proName].type
      }
    })
  }
  return []
}

export function dealPaths(resource: Record<string, any>, resourceName: string): IDocumentProps[] {
  const {
    paths,
    components: { schemas }
  } = resource
  if (!paths) {
    return []
  }
  return Object.keys(paths).map((x) => {
    const pathTmp = paths[x]
    const pathKes = Object.keys(pathTmp)
    const pathObject = pathTmp[pathKes[0]]
    const response = pathObject.responses

    // ------------------ 请求参数处理 ------------------
    const consumesArr = pathObject.consumes ?? []
    let parameters = pathObject.parameters ?? []
    // 判断是否包含requestBody
    if (Object.prototype.hasOwnProperty.call(pathObject, 'requestBody')) {
      const bodyParameter = pathObject.requestBody
      if (Object.prototype.hasOwnProperty.call(bodyParameter, 'content')) {
        const bodyContent = bodyParameter.content
        Object.keys(bodyContent).forEach((consume) => {
          const consumeBody = bodyContent[consume]
          if (Object.prototype.hasOwnProperty.call(consumeBody, 'schema')) {
            // 判断是否包含schema
            const { schema } = consumeBody
            if (!consumesArr.includes(consume)) {
              // 储存数据请求类型
              consumesArr.push(consume)
            }
            if (schema.properties) {
              // 此处判断properties,如果有properties,说明有属性,非ref
              // 整理properties 放入请求参数
              parameters = [...parameters, ...dealProperties(schema)]
            } else if (schema.$ref) {
              // 为ref，从components中获取参数
              const className = getClassName(schema.$ref)
              if (className) {
                parameters = [...parameters, ...dealProperties(schemas[className], true)]
              }
            }
          }
        })
      }
    }
    // ------------------ 响应状态处理 ------------------
    const responsesData: any[] = [] // 响应状态数组
    Object.keys(response).forEach((status) => {
      const resObj = response[status]
      const commonObj = {
        code: status,
        description: resObj.description
      }
      if (resObj.content) {
        const resContent = resObj.content
        Object.keys(resContent).forEach((cKey) => {
          const respContentProduces = resContent[cKey]
          if (respContentProduces.schema) {
            const { schema } = respContentProduces
            const schemaName = getClassName(schema.$ref)
            if (schemaName) {
              responsesData?.push({ ...commonObj, schema: schemaName })
            }
          }
        })
      } else {
        responsesData?.push(commonObj)
      }
    })
    // ------------------ 响应参数处理 ------------------
    const responsesParameters: any[] = []
    responsesData.forEach((item) => {
      if (item.schema) {
        responsesParameters.push({
          code: item.code,
          data: item.schema ? dealResponses(item.schema, schemas) : [],
          responseText: item.schema ? JSON.stringify(dealToJson(item.schema, schemas, {})) : ''
        })
      }
    })

    return {
      api: x,
      method: pathKes[0],
      summary: pathObject.summary,
      produces: pathObject.produces,
      consumes: consumesArr,
      deprecated: pathObject.deprecated,
      parameters,
      operationId: pathObject.operationId,
      responses: responsesData as IResponseProps[],
      resourceName,
      tags: pathObject.tags,
      responsesParameters
    } as IDocumentProps
  })
}

export function groupBy<T, K extends keyof T>(data: T[], key: K) {
  const map = new Map()
  data.forEach((item) => {
    if (!map.has((item[key] as any)[0])) {
      map.set(
        (item[key] as any)[0],
        data.filter((x) => (x[key] as any)[0] === (item[key] as any)[0])
      )
    }
  })
  return Object.fromEntries(Array.from(map).map((item) => [item[0], item[1]]))
}

// 对象
export function getGroupObject(list: any, attr: string) {
  const map = new Map()
  list.forEach((item: any, index: number, arr: any[]) => {
    if (!map.has(item[attr])) {
      map.set(
        item[attr],
        arr.filter((a) => a[attr] === item[attr])
      )
    }
  })
  return Object.fromEntries(Array.from(map).map((item) => [item[0], item[1]]))
}

export function generateApiGroup(documentPaths: IDocumentProps[], groupName: string): MenuProps[] {
  if (documentPaths.length === 0) {
    return []
  }
  const map = new Map()
  const key = 'tags'
  documentPaths.forEach((item) => {
    if (!map.has((item[key] as any)[0])) {
      map.set(
        (item[key] as any)[0],
        documentPaths.filter((x) => (x[key] as any)[0] === (item[key] as any)[0])
      )
    }
  })
  const result = Array.from(map).map((item) => [item[0], item[1]])
  const routeMap = result.map((tags: [string, IDocumentProps[]]) => {
    const name = tags[0].trim()
    const children = tags[1]
    const route: MenuProps = {
      path: `/${name}`,
      title: name,
      name,
      key: `${groupName}/${name}`, // 用户匹配菜单的key
      children: []
    }
    children.length > 0 &&
      children.forEach((x) => {
        const tag = x.tags[0].trim()
        const child = {
          title: x.summary,
          name: x.summary,
          key: x.operationId, // 子菜单的key
          props: JSON.parse(JSON.stringify(x)),
          path: `/${x.resourceName}/${tag}/${x.summary}/${x.operationId}`,
          params: { title: x.summary }
        }
        route?.children?.push(child)
      })
    return route
  })
  return routeMap
}

export function generateDocRoute(documentPaths: IDocumentProps[]): RouteRecordRaw[] {
  if (documentPaths.length === 0) {
    return []
  }
  const map = new Map()
  const key = 'tags'
  documentPaths.forEach((item) => {
    if (!map.has((item[key] as any)[0])) {
      map.set(
        (item[key] as any)[0],
        documentPaths.filter((x) => (x[key] as any)[0] === (item[key] as any)[0])
      )
    }
  })
  const result = Array.from(map).map((item) => [item[0], item[1]])
  console.log(result)
  const routeMap = result.map((x: [string, IDocumentProps[]]) => {
    const name = x[0].trim()
    const children = x[1]
    const route: RouteRecordRaw = {
      path: `/${name}`, // `/${md5(name)}`
      name, //  md5(name)
      component: () => import('@/layout/components/empty-content/index.vue'),
      meta: {
        title: name,
        requiresAuth: true,
        icon: renderSvgIcon('doc'),
        order: 9
      },
      children: []
    }
    children.length > 0 &&
      children.forEach((x) => {
        // const name = x.summary.trim() + x.operationId.trim()
        const methodUpperCase = x.method.toUpperCase() as SupportMethodType
        const child = {
          path: x.operationId.trim(), // `${md5(name)}`
          component: () => import('@/views/document/index.vue'),
          name: x.operationId.trim(), // md5(name),
          props: { ...x },
          meta: {
            title: x.summary.trim(),
            icon: h(
              'span',
              {
                style: {
                  'display': 'inline-block',
                  'width': '38px',
                  'font-size': '12px',
                  'font-weight': 'bold'
                },
                class: ['k-api', `k-api-${x.method}`]
              },
              {
                default: () => (x.method !== 'post' ? methodUpperCase.substring(0, 3) : methodUpperCase)
              }
            ),
            order: 0
          }
        }
        route.children.push(child)
      })
    return route
  })
  return Array.from(routeMap)
}

export function dealConsumes(consumes: string[]) {}
